#include "helper.h"
#include "monitor.h"
#include "all-instr.h"
typedef void (*op_fun)(uint32_t);
extern char assembly[80];
extern uint32_t instr;
extern Operands ops_decoded;
extern op_fun opcode_table[64];

/* invalid opcode */
make_helper(inv)
{

	uint32_t temp;
	temp = instr_fetch(pc, 4);

	uint8_t *p = (void *)&temp;
	printf("invalid opcode(pc = 0x%08x): %02x %02x %02x %02x ...\n\n",
		   pc, p[3], p[2], p[1], p[0]);

	printf("There are two cases which will trigger this unexpected exception:\n\
1. The instruction at pc = 0x%08x is not implemented.\n\
2. Something is implemented incorrectly.\n",
		   pc);
	printf("Find this pc value(0x%08x) in the disassembling result to distinguish which case it is.\n\n", pc);

	assert(0);
}

/* stop temu */
make_helper(temu_trap)
{

	printf("\33[1;31mtemu: HIT GOOD TRAP\33[0m at $pc = 0x%08x\n\n", cpu.pc);

	temu_state = END;
}

static void decode_offs16_type(uint32_t instr)
{

	op_src1->type = OP_TYPE_REG;
	op_src1->reg = (instr >> 5) & 0x0000001F;
	op_src1->val = reg_w(op_src1->reg);

	op_src2->type = OP_TYPE_REG;
	op_src2->reg = instr & 0x0000001F;
	op_src2->val = reg_w(op_src2->reg);

	op_dest->type = OP_TYPE_IMM;
	op_dest->imm = (instr >> 10) & 0x0000FFFF;
	op_dest->val = op_dest->imm;
}

make_helper(beq)
{
	decode_offs16_type(instr);
	if (op_src1->val == op_src2->val)
	{
		uint32_t offs = ((op_dest->val << 2) >> 17) ? ((op_dest->val << 2) | 0xFFFC0000) : (op_dest->val << 2);
		pc = pc + offs;
		cpu.pc = cpu.pc + offs;
		sprintf(assembly, "beq\t%s,\t%s,\t0x%04x", REG_NAME(op_src1->reg), REG_NAME(op_src2->reg), op_dest->imm);
		instr = instr_fetch(pc, 4);
		ops_decoded.opcode1 = instr >> 26;
		opcode_table[ops_decoded.opcode1](pc);
	}
}

make_helper(bne)
{
	decode_offs16_type(instr);
	if (op_src1->val != op_src2->val)
	{
		uint32_t offs = ((op_dest->val << 2) >> 17) ? ((op_dest->val << 2) | 0xFFFC0000) : (op_dest->val << 2);
		pc = pc + offs;
		cpu.pc = cpu.pc + offs;
		sprintf(assembly, "bne\t%s,\t%s,\t0x%04x", REG_NAME(op_src1->reg), REG_NAME(op_src2->reg), op_dest->imm);
		instr = instr_fetch(pc, 4);
		ops_decoded.opcode1 = instr >> 26;
		opcode_table[ops_decoded.opcode1](pc);
	}
}

make_helper(blt)
{
	decode_offs16_type(instr);
	int rj = op_src1->val;
	int rd = op_src2->val;
	if (rj < rd)
	{
		uint32_t offs = ((op_dest->val << 2) >> 17) ? ((op_dest->val << 2) | 0xFFFC0000) : (op_dest->val << 2);
		pc = pc + offs;
		cpu.pc = cpu.pc + offs;
		sprintf(assembly, "blt\t%s,\t%s,\t0x%04x", REG_NAME(op_src1->reg), REG_NAME(op_src2->reg), op_dest->imm);
		instr = instr_fetch(pc, 4);
		ops_decoded.opcode1 = instr >> 26;
		opcode_table[ops_decoded.opcode1](pc);
	}
}
